﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace DimensionsHelper.Common.Utils;

public static class EnumerableHelper
{
    /// <summary>
    ///     判断两个集合中的字符是否完全重合。如果两个集合长度相同，判断两个集合中的内容是否相同；如果两个集合长度不同，判断
    ///     长度比较短的集合中的元素是否都存在于长度比较长的集合中。
    /// </summary>
    /// <param name="set1">第一个集合</param>
    /// <param name="set2">第二个集合</param>
    /// <param name="difference">包含两个集合中不同部分的集合</param>
    /// <returns>如果集合内容重合，返回true，否则，返回false</returns>
    public static bool IsSetCoincidence(ISet<string> set1, ISet<string> set2, out HashSet<string> difference)
    {
        if (set1.Count == 0 || set2.Count == 0)
        {
            difference = null!;
            return false;
        }

        HashSet<string> baseSet;
        HashSet<string> compareSet;

        if (set2.Count > set1.Count)
        {
            baseSet = [..set2];
            compareSet = [..set1];
        }
        else
        {
            baseSet = [..set1];
            compareSet = [..set2];
        }

        difference = baseSet;
        return compareSet.All(item => baseSet.Remove(item));
    }

    /// <summary>
    ///     判断字典的键集合和给定字符串集合内容是否重合，即一个是否完全包含于另一个。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="dict">给定字典，需要键类型为字符串</param>
    /// <param name="textSet">给定字符串集合</param>
    /// <param name="difference">包含两个集合不同部分的集合</param>
    /// <returns>判定成功返回true，否则返回false</returns>
    public static bool IsSetCoincidence<T>(IReadOnlyDictionary<string, T> dict, ISet<string> textSet,
        out HashSet<string> difference)
    {
        return IsSetCoincidence(new HashSet<string>(dict.Keys), textSet, out difference);
    }


    /// <summary>
    ///     将字符串列表转换为枚举类型
    /// </summary>
    /// <param name="stringList">字符串列表</param>
    /// <param name="map">字符串列表中元素的对应值</param>
    /// <param name="incompatibleValue">互斥值，此值和其他值不能同时存在</param>
    public static T ToEnumFlags<T>(this IEnumerable<string> stringList, IReadOnlyDictionary<string, T> map,
        string? incompatibleValue = null) where T : Enum
    {
        int val = 0;

        foreach (string item in stringList)
        {
            if (!map.TryGetValue(item, out var member))
            {
                continue;
            }

            if (!string.IsNullOrEmpty(incompatibleValue) && item == incompatibleValue)
            {
                return member;
            }

            val |= (int)(object)member;
        }

        return (T)Enum.ToObject(typeof(T), val);
    }

    
    public static void FromEnumValue<T>(this ICollection<string> targetStringList, T enumValue,
        IReadOnlyDictionary<string, T> map,
        string? incompatibleValue = null) where T : Enum
    {
        targetStringList.Clear();

        int enumInteger = (int)Enum.ToObject(typeof(T), enumValue);

        foreach (KeyValuePair<string, T> pair in map)
        {
            if ((enumInteger & (int)Enum.ToObject(typeof(T), pair.Value)) != 0)
            {
                targetStringList.Add(pair.Key);
            }
        }

        if (targetStringList.Count == 0 && !string.IsNullOrEmpty(incompatibleValue))
        {
            targetStringList.Add(incompatibleValue!);
        }
    }
    
    
    public static List<string> ToStringList<T>(this T enumValue, IDictionary<string, T> map,
        string? incompatibleValue = null) where T : Enum
    {
        int intVal = (int)Enum.ToObject(typeof(T), enumValue);

        List<string> list =
            (from item in map where (intVal & (int)(object)item.Value) != 0 select item.Key).ToList();

        if (list.Count == 0 && !string.IsNullOrEmpty(incompatibleValue))
        {
            list.Add(incompatibleValue!);
        }

        return list;
    }
}